/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Kernel Module                                  */
/*                                                                           */
/*    Copyright (C) 2013 Laszlo Arvai                                        */
/*    All rights reserved.                                                   */
/*                                                                           */
/*    This software may be modified and distributed under the terms          */
/*    of the BSD license.  See the LICENSE file for details.                 */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    Resource file access routines                                          */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// include files
#include <krnlResourceFile.h>
#include "drvMemoryAccess.h"

///////////////////////////////////////////////////////////////////////////////
// Constants
#define res_MAGIC_HEADER 0x5244 // 'DR'
#define res_CRC_POLYNOMIAL 0x1021
#define res_CRC_INITIAL_VALUE 0xffff

///////////////////////////////////////////////////////////////////////////////
// Module local variables
dosROMAddress l_string_resource = 0;

///////////////////////////////////////////////////////////////////////////////
// Init resource access
void krnlInitResourceFile(void)
{
  dosBool success = dosTrue;
  dosByte i;
  dosWord ch;
  dosDWord size;
  dosROMAddress address;
  dosWord crc;
	
  // check header
  if( success && dosROMReadWord( 0 ) != res_MAGIC_HEADER )
    success = dosFalse;

  // TODO: check version

  // Check CRC
  if( success )
  {
    // get size
    size = dosROMReadDWord( 6 ) - 6;
    address = 6;
    crc = res_CRC_INITIAL_VALUE;

    // go through buffer
    while(size > 0) 
    {
      // get byte
      ch = dosROMReadByte( address++ );
      ch <<= 8; 

      // go through all bits
      for( i=0; i<8; i++) 
      {
        if( ((crc ^ ch) & 0x8000) != 0 ) 
        {
          // shift checksum
          crc <<= 1; 

          // xor polynomial
          crc ^= res_CRC_POLYNOMIAL;
        }
  	    else 
        {
          // shift checksum
          crc <<= 1; 
        }
        
        // shift data
        ch = ch << 1; 
	    } 

      // next byte
      size--;
    }

    // compare CRC
    if( crc != dosROMReadWord( 4 ) )
      success = dosFalse;
  } 

  // store string resource address
  if( success )
  {
    l_string_resource = krnlGetResourceAddress( 0x47525453ul );
  }
}

///////////////////////////////////////////////////////////////////////////////
// Get resource address
dosROMAddress krnlGetResourceAddress( dosDWord in_resource_id )
{
  dosWord chunk_count;
  int i;
  dosROMAddress address;

  // get chunk count
  chunk_count = dosROMReadWord(10);

  // find chunk
  address = 12;
  i = 0;
  while( i < chunk_count && dosROMReadDWord( address ) != in_resource_id )
  {
    address += sizeof( dosDWord ) + sizeof( dosDWord );
    i++;
  }

  // if found
  if( i < chunk_count )
  {
    return (dosROMAddress)dosROMReadDWord( address + sizeof( dosDWord ) );
  }
  else
  {
    return 0;
  }
}

///////////////////////////////////////////////////////////////////////////////
// Get resource size
dosDWord krnlGetResourceSize( dosDWord in_resource_id )
{
  dosWord chunk_count;
  int i;
  dosROMAddress address;
  dosROMAddress next_address = 0;

  // get chunk count
  chunk_count = dosROMReadWord(10);

  // find chunk
  address = 12;
  i = 0;
  while( i < chunk_count )
  {
    if( i + 1 == chunk_count )
      next_address = dosROMReadDWord( 6 );
    else
      next_address = dosROMReadDWord( address + 12 );

    if( dosROMReadDWord( address ) == in_resource_id )
      break;

    address += sizeof( dosDWord ) + sizeof( dosDWord );
    i++;
  }

  // if found
  if( i < chunk_count )
  {
    return next_address - dosROMReadDWord( address + 4 );
  }
  else
  {
    return 0;
  }
}

///////////////////////////////////////////////////////////////////////////////
// String resource functions
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Get resource string length
dosDWord krnlGetResourceStringLength( dosHandle in_string_handle )
{
  dosDWord length = 0;
  dosByte data;
  dosROMAddress address;

  address = /*l_string_resource +*/ in_string_handle;

  do
  {
    data = dosROMReadByte( address++ );

    length = (length << 7) + (data & 0x7f);
  } while( data > 127 );

  return length;
}

///////////////////////////////////////////////////////////////////////////////
// Get resorce string
dosROMAddress krnlGetResourceString( dosHandle in_string_handle )
{
  dosROMAddress address;

  address = /* l_string_resource + */ in_string_handle;

  while( dosROMReadByte( address++ ) > 127 );

  return address;
}
